from django.db import models
from django.contrib.auth.models import User  # 导入django的用户模型


# Create your models here.



class Asset(models.Model):
    """ 所有资产的共有数据表 """
    asset_type_choice = (
        ('server', '服务器'),
        ('networkdevice', '网络设备'),
        ('storagedevice', '存储设备'),
        ('securitydevice', '安全设备'),
        ('software', '软件资产'),
    )

    asset_status = (      #  资产状态
        (0, '在线'),
        (1, '下线'),
        (2, '未知'),
        (3, '故障'),
        (4, '备用'),
    )

    asset_type = models.CharField(choices=asset_type_choice, max_length=64, default='server', verbose_name='资产类型')
    name = models.CharField('资产名称', max_length=64, unique=True) # 名称唯一
    sn = models.CharField('资产序列号', max_length=128, unique=True) # 序列号唯一
    business_unit = models.ForeignKey('BusinessUnit', null=True, blank=True, verbose_name='所属业务线', on_delete=models.CASCADE)
    status = models.SmallIntegerField(choices=asset_status, default=0, verbose_name='设备状态')


    manufacturer = models.ForeignKey('Manufacturer', null=True, blank=True, verbose_name='制造商', on_delete=models.CASCADE)
    manage_ip = models.GenericIPAddressField('管理IP', null=True, blank=True)
    tags = models.ManyToManyField('Tag', blank=True, verbose_name='标签')
    admin = models.ForeignKey(User, null=True, blank=True, verbose_name='管理员', related_name='admin', on_delete=models.CASCADE)
    idc = models.ForeignKey('IDC', null=True, blank=True, verbose_name='所在机房', on_delete=models.CASCADE)
    contract = models.ForeignKey('Contract', null=True, blank=True, verbose_name='合同', on_delete=models.CASCADE)

    purchase_day = models.DateField('购买日期', null=True, blank=True)
    expire_day = models.DateField('过保日期', null=True, blank=True)
    price = models.FloatField('购买价格', null=True, blank=True)

    approved_by = models.ForeignKey(User, null=True, blank=True, verbose_name='批准人', related_name='approved_by', on_delete=models.CASCADE)

    memo = models.TextField('备注', null=True, blank=True)
    c_time = models.DateTimeField('批准日期', auto_now_add=True)
    m_time = models.DateTimeField('更新日期', auto_now_add=True)


    def __str__(self):
        return '<%s> %s' % (self.get_asset_type_display(), self.name)

    class Meta:
        verbose_name = '资产总表'
        verbose_name_plural = '资产总表'
        ordering = ['-c_time']



class Server(models.Model):
    """服务器设备"""
    sub_asset_type_choice = (
        (0, 'PC服务器'),
        (1, '刀片机'),
        (2, '小型机'),
    )

    created_by_choice = (
        ('auto', '自动添加'),
        ('manual', '手工录入'),
    )
    asset = models.OneToOneField('Asset', on_delete=models.CASCADE, verbose_name='资产')
    sub_asset_type = models.SmallIntegerField('服务器类型', choices=sub_asset_type_choice, default=0)
    created_by = models.CharField('添加方式', choices=created_by_choice, max_length=32, default='auto')
    hosted_on = models.ForeignKey('self', related_name='hosted_on_server',
                                  blank=True, null=True, verbose_name='宿主机',
                                  on_delete=models.CASCADE)
    model = models.CharField('服务器型号', max_length=128, null=True, blank=True)
    raid_type = models.CharField('Raid类型', null=True, blank=True, max_length=512)

    os_type = models.CharField('操作系统类型', max_length=64, blank=True, null=True)
    os_distribution = models.CharField('发行版本', max_length=64, blank=True, null=True)
    os_release = models.CharField('操作系统版本', max_length=64, blank=True, null=True)

    def __str__(self):
        return '%s--%s--%s<sn:%s>' % (self.asset.name, self.get_sub_asset_type_display(), self.model, self.asset.sn)

    class Mate:
        verbose_name = '服务器'
        verbose_name_plural = '服务器'


class SecurityDevice(models.Model):
    """安全设备"""
    sub_asset_type_choice = (
        (0, '防火墙'),
        (1, '入侵检测设备'),
        (2, '互联网网关'),
        (4, '运维审计系统'),
    )

    asset = models.OneToOneField('Asset', on_delete=models.CASCADE)
    sub_asset_type = models.SmallIntegerField('安全设备类型', choices=sub_asset_type_choice, default=0)

    def __str__(self):
        return self.asset.name + '--' + self.get_sub_asset_type_display() + 'id:%s' % self.id

    class Meta:
        verbose_name = '安全设备'
        verbose_name_plural = '安全设备'


class StorageDevice(models.Model):
    """存储设备"""
    sub_asset_type_choice = (
        (0, '磁盘阵列'),
        (1, '网络储存器'),
        (2, '磁带库'),
        (4, '磁带机'),
    )

    asset = models.OneToOneField('Asset', on_delete=models.CASCADE)
    sub_asset_type = models.SmallIntegerField('存储设备类型',
                                              choices=sub_asset_type_choice,
                                              default=0)
    def __str__(self):
        return self.asset.name + '--' + self.get_sub_asset_type_display() + 'id:%s' % self.id

    class Meta:
        verbose_name = '存储设备'
        verbose_name_plural = '存储设备'


class NetworkDevice(models.Model):
    """网络设备"""
    sub_asset_type_choice = (
        (0, '路由器'),
        (1, '交换机'),
        (2, '负载均衡'),
        (4, 'VPN设备'),
    )

    asset = models.OneToOneField('Asset', on_delete=models.CASCADE)
    sub_asset_type = models.SmallIntegerField('网络设备类型', choices=sub_asset_type_choice, default=0)

    vlan_ip = models.GenericIPAddressField('VLanIP', blank=True, null=True)
    intranet_ip = models.GenericIPAddressField('内网IP', blank=True, null=True)

    model = models.CharField(max_length=128, null=True, blank=True, verbose_name='网络设备型号')
    firmware = models.CharField('设备固件版本', max_length=128, null=True, blank=True)
    port_num = models.SmallIntegerField('端口个数', null=True, blank=True)
    device_detail = models.TextField('详细配置', null=True, blank=True)

    def __str__(self):
        return '%s--%s--%s <sn:%s>' % (self.asset.name, self.get_sub_asset_type_display(), self.model, self.asset.sn)

    class Meta:
        verbose_name = '网络设备'
        verbose_name_plural = '网络设备'

class Software(models.Model):
    """只保存付费购买的软件"""
    sub_asset_type_choice = (
        (0, '操作系统'),
        (1, '办公\软件开发'),
        (2, '业务软件'),
    )

    sub_asset_type = models.SmallIntegerField('软件类型', choices=sub_asset_type_choice, default=0)
    license_num = models.IntegerField('授权数量', default=1)
    version = models.CharField('软件/系统版本', max_length=64, unique=True, help_text='例如: CentOS release 6.7 (Final)')

    def __str__(self):
        return '%s--%s' % (self.get_sub_asset_type_display(), self.version)

    class Meta:
        verbose_name = '软件/系统'
        verbose_name_plural = '软件/系统'


#  机房、制造商、业务线、合同、资产标签
class IDC(models.Model):
    """机房"""
    name = models.CharField('机房名称', max_length=64, unique=True)
    memo = models.CharField('备注', max_length=128, blank=True, null=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '机房'
        verbose_name_plural = '机房'

class Manufacturer(models.Model):
    """厂商"""
    name = models.CharField('厂商名称', max_length=64, unique=True)
    telephone = models.CharField('支持电话', max_length=30, blank=True, null=True)
    memo = models.CharField('备注', max_length=128,blank=True, null=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '厂商'
        verbose_name_plural = '厂商'

class BusinessUnit(models.Model):
    """业务线"""
    parent_unit = models.ForeignKey('self', blank=True, null=True,
                                    related_name='parent_level',
                                    on_delete=models.CASCADE)
    name = models.CharField('业务线', max_length=64, unique=True)
    memo = models.CharField('备注', max_length=64, blank=True, null=True)

    def __str__(self):
        return self.name
    class Meta:
        verbose_name_plural = '业务线'
        verbose_name = '业务线'

class Contract(models.Model):
    """合同"""
    sn = models.CharField('合同号', max_length=128, unique=True)
    name = models.CharField('合同名称', max_length=64)
    memo = models.TextField('备注', blank=True, null=True)
    price = models.IntegerField('合同金额')
    detail = models.TextField('合同详细', blank=True, null=True)
    start_day = models.DateField('开始日期', blank=True, null=True)
    end_day = models.DateField('失效日期', blank=True, null=True)
    license_num = models.IntegerField('license数量', blank=True, null=True)
    c_day = models.DateField('创建日期', auto_now_add=True)
    m_day = models.DateField('修改日期', auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '合同'
        verbose_name_plural = '合同'


class Tag(models.Model):
    """标签"""
    name = models.CharField('标签名', max_length=32, unique=True)
    c_dat = models.DateField('创建日期', auto_now_add=True)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = '标签'
        verbose_name = '标签'

# CPU模型
class CPU(models.Model):
    """CPU组件"""
    asset = models.OneToOneField('Asset', on_delete=models.CASCADE)
    cpu_model = models.CharField('CPU型号', max_length=128, blank=True, null=True)
    cpu_count = models.PositiveSmallIntegerField('物理CPU个数', default=1)
    cpu_core_count = models.PositiveSmallIntegerField('CPU核数', default=1)

    def __str__(self):
        return self.asset.name + ': ' + self.cpu_model
    class Meta:
        verbose_name = 'CPU'
        verbose_name_plural = 'CPU'

# RAM模型
class RAM(models.Model):
    """内存组件"""
    asset = models.ForeignKey('Asset', on_delete=models.CASCADE)
    sn = models.CharField('SN型号', max_length=128, blank=True, null=True)
    model = models.CharField('内存型号', max_length=128, blank=True,null=True)
    manufacturer = models.CharField('内存制造商', max_length=128, blank=True, null=True)
    slot = models.CharField('插槽', max_length=64)
    capacity = models.IntegerField('内存大小（GB）', blank=True, null=True)

    def __str__(self):
        return '%s: %s: %s: %s' % (self.asset.name, self.model, self.slot, self.capacity)

    class Meta:
        verbose_name = '内存'
        verbose_name_plural = '内存'
        unique_together = ('asset', 'slot') # 同一资产下的内存，根据插槽的不同，必须唯一


# 硬盘模型
class Disk(models.Model):
    """储存设备"""
    disk_interface_type_choice = (
        ('SATA', 'SATA'),
        ('SAS', 'SAS'),
        ('SCSI', 'SCSI'),
        ('SSD', 'SSD'),
        ('unknown', 'unknown'),
    )
    asset = models.ForeignKey('Asset', on_delete=models.CASCADE)
    sn = models.CharField('硬盘SN号', max_length=128)
    slot = models.CharField('所在插槽位', max_length=64, blank=True, null=True)
    model = models.CharField('磁盘型号', max_length=128, blank=True, null=True)
    capacity = models.FloatField('磁盘容量（GB）', blank=True, null=True)
    manufacturer = models.CharField('磁盘制造商', max_length=128, blank=True, null=True)
    interface_type = models.CharField('接口类型', max_length=16, choices=disk_interface_type_choice
                                      , default='unknown')

    def __str__(self):
        return '%s:  %s:  %s:  %sGB' % (self.asset.name, self.model, self.slot, self.capacity)

    class Meta:
        verbose_name = '硬盘'
        verbose_name_plural = '硬盘'
        unique_together = ('asset', 'sn')


# 网卡模型
class NIC(models.Model):
    """网卡组件"""
    asset = models.ForeignKey('Asset', on_delete=models.CASCADE)
    name = models.CharField('网卡名称', max_length=64, blank=True, null=True)
    model = models.CharField('网卡型号', max_length=128)
    mac = models.CharField('MAC地址', max_length=64)
    ip_address = models.GenericIPAddressField('IP地址', blank=True, null=True)
    net_mask = models.CharField('掩码', max_length=64, blank=True, null=True)
    bonding = models.CharField('绑定地址', max_length=64, blank=True, null=True)

    def __str__(self):
        return '%s:  %s:  %s' % (self.asset.name, self.model, self.mac)
    class Meta:
        verbose_name = '网卡'
        verbose_name_plural = '网卡'
        unique_together = ('asset', 'model', 'mac')
        # 资产、型号和mac必须联合唯一。防止虚拟机中的特殊情况发生错误。

# 日志模型
# 记录事件名称、类型、关联的资产、子事件、事件详情、谁导致的、发生时间。
# 尤其要注意的是，事件日志不能随着关联资产的删除被一并删除，
# 也就是我们设置on_delete=models.SET_NULL的意义！
class EventLog(models.Model):
    """日志，在关联对象被删除的时候，不能一并删除，需保留日志。
    因此，on_delete=models.SET_NULL"""
    name = models.CharField('事件名称', max_length=128)
    event_type_choice = (
        (0, '其他'),
        (1, '硬件变更'),
        (2, '新增配件'),
        (3, '设备下线'),
        (4, '设备上线'),
        (5, '定期维护'),
        (6, '业务上线\更新\变更'),
    )

    asset = models.ForeignKey('Asset', on_delete=models.SET_NULL,
                              blank=True, null=True)  # 当资产审批成功时有这项数据
    new_asset = models.ForeignKey('NewAssetApprovalZone', on_delete=models.SET_NULL
                                  ,blank=True, null=True)  # 当资产审批失败时有这项数据
    event_type = models.SmallIntegerField('事件类型', choices=event_type_choice, default=4)
    component = models.CharField('事件子项', max_length=128, null=True, blank=True)
    detail = models.TextField('事件详细')
    date = models.DateTimeField('事件事件', auto_now_add=True)
    user = models.ForeignKey(User, blank=True, null=True, verbose_name='事件执行人',
                             on_delete=models.SET_NULL) # 自动更新资产数据时没有执行人
    memo = models.TextField('备注', blank=True, null=True)

    def __str__(self):
        return self.name
    class Meata:
        verbose_name = '事件记录'
        verbose_name_plural = '事件记录'


class NewAssetApprovalZone(models.Model):
    """新资产待审批区"""
    sn = models.CharField('资产SN号', max_length=128, unique=True)
    asset_type_choice = (
        ('server', '服务器'),
        ('networkdevice', '网络设备'),
        ('storagedevice', '存储设备'),
        ('securitydevice', '安全设备'),
        ('IDC', '机房'),
        ('software', '软件资产'),
    )
    asset_type = models.CharField('资产类型', choices=asset_type_choice, max_length=64,
                                  blank=True, null=True, default='server')
    manufacturer = models.CharField('生产厂商', max_length=64, blank=True, null=True)
    model = models.CharField('型号', max_length=128, blank=True, null=True)
    ram_size = models.PositiveIntegerField('内存大小', blank=True, null=True)
    cpu_model = models.CharField('CPU型号', null=True, blank=True, max_length=128)
    cpu_count = models.PositiveSmallIntegerField(blank=True, null=True)
    cpu_core_count = models.PositiveSmallIntegerField(blank=True, null=True)
    os_distribution = models.CharField(max_length=64, blank=True, null=True)
    os_type = models.CharField(max_length=64, blank=True, null=True)
    os_release = models.CharField(max_length=64, blank=True, null=True)

    data = models.TextField('资产数据') # 必填

    c_time = models.DateTimeField('汇报日期', auto_now_add=True)
    m_time = models.DateTimeField('更新日期', auto_now_add=True)
    approved = models.BooleanField('是否批准', default=False)

    def __str__(self):
        return self.sn

    class Meta:
        verbose_name = '新上线待批准资产'
        verbose_name_plural = '新上线待批准资产'
        ordering = ['-c_time']







